package OBJ;

import DataStructure.Face;
import DataStructure.Model;
import org.joml.Vector3f;

import java.awt.*;
import java.util.ArrayList;
import java.util.List;

public class VoxelLoader {
    public int[][][] voxelGrid;
    public List<Color>[][][] voxelColorList;
    public  Color[][][] voxelColor;
    private Model model;
    private List<Vector3f> vertices;
    private List<Face> faces;
    public float voxelSize;
    public int voxelLength;
    public int voxelWidth;
    public int voxelHeight;

    public float minX ;
    public float maxX ;
    public float minY ;
    public float maxY ;
    public float minZ ;
    public float maxZ ;
    public Vector3f boxMin;
    public Vector3f boxMax;
    public VoxelLoader(Model model){
        this.model = model;
        this.vertices = model.getVertices();
        this.faces = model.getFaces();
        loadBox();
    }

    private void loadBox(){
        // 1. 初始化最小/最大值（用第一个顶点作为起点）
        minX = (float) vertices.parallelStream()
          .mapToDouble(v -> v.x)
          .min().orElse(0);
        maxX = (float) vertices.parallelStream()
          .mapToDouble(v -> v.x)
          .max().orElse(0);
        minY = (float) vertices.parallelStream()
          .mapToDouble(v -> v.y)
          .min().orElse(0);
        maxY = (float) vertices.parallelStream()
          .mapToDouble(v -> v.y)
          .max().orElse(0);
        minZ = (float) vertices.parallelStream()
          .mapToDouble(v -> v.z)
          .min().orElse(0);
        maxZ = (float) vertices.parallelStream()
                .mapToDouble(v -> v.z)
                .max().orElse(0);
        boxMin = new Vector3f(minX, minY, minZ);
        boxMax = new Vector3f(maxX, maxY, maxZ);
    }
    public void loadVoxel(int heightLimit){
        voxelSize = (boxMax.y - boxMin.y) / heightLimit;
         voxelLength = (int) ((boxMax.x - boxMin.x) / voxelSize) + 1;
         voxelWidth = (int) ((boxMax.z - boxMin.z) / voxelSize) + 1;
         voxelHeight = (int) ((boxMax.y - boxMin.y) / voxelSize) + 1;


        voxelGrid = new int[voxelLength][voxelHeight][voxelWidth];
        voxelColor = new Color[voxelLength][voxelHeight][voxelWidth];
        voxelColorList = new List[voxelLength][voxelHeight][voxelWidth];

        for(Model.Material m : model.materials){
            for(Face f: m.faces){
                int[] vIndices = f.getVertexIndices();
                if (vIndices.length < 3) continue;

                Vector3f v0 = vertices.get(vIndices[0]);
                Vector3f v1 = vertices.get(vIndices[1]);
                Vector3f v2 = vertices.get(vIndices[2]);
                Vector3f CenterGra = new Vector3f(
                        (v0.x + v1.x + v2.x) / 3,
                        (v0.y + v1.y + v2.y) / 3,
                        (v0.z + v1.z + v2.z) / 3
                );
// 计算体素索引
// 在VoxelLoader的loadVoxel方法中添加体素索引边界检查
                int x = (int) ((CenterGra.x - boxMin.x) / voxelSize);
                int y = (int) ((CenterGra.y - boxMin.y) / voxelSize);
                int z = (int) ((CenterGra.z - boxMin.z) / voxelSize);



                if(voxelColorList[x][y][z] == null)
                    voxelColorList[x][y][z] = new ArrayList<>();
                if(isInsideModel(f,CenterGra)){
                    voxelGrid[x][y][z] = 1;
                    voxelColorList[x][y][z].add(getColorFromFace(f));
                }


            }
        }
        for (int x = 0; x < voxelLength; x++) {
            for (int y = 0; y < voxelHeight; y++) {
                for (int z = 0; z < voxelWidth; z++) {
                    if(voxelColorList[x][y][z] == null)
                    {
                        voxelGrid[x][y][z] = 0;
                        continue;
                    }
                    float redSum = 0, greenSum = 0, blueSum = 0;
                    int num = voxelColorList[x][y][z].size();
                    if(num == 0 ) {
                        voxelColor[x][y][z] = null;
                        voxelGrid[x][y][z] = 0;
                        continue;
                    }
                    else voxelGrid[x][y][z] = 1;
                    for (Color c : voxelColorList[x][y][z]) {
                        redSum += c.getRed();
                        greenSum += c.getGreen();
                        blueSum += c.getBlue();
                    }

                    int avgRed = Math.round(redSum / num);
                    int avgGreen = Math.round(greenSum / num);
                    int avgBlue = Math.round(blueSum / num);

                    voxelColor[x][y][z] = new Color(avgRed, avgGreen, avgBlue);
                }

            }

        }
    }
    private Color getColorFromFace(Face f){
        if(f.faceColor != null) return f.faceColor;
        else {
            return f.getColorofFace(model);
        }
    }
    private boolean isInsideModel(Face f,Vector3f point) {
        // 计算当前面的法线
        Vector3f normal = f.calculateFaceNormal(model);
        // 计算重心
        Vector3f centroid = point;
        // 沿法线方向移动微小距离得到外部测试点
        Vector3f testPoint = centroid.add(normal.mul(1e-6F));
        // 发射射线并统计相交次数
        int hitCount = countRayIntersections(testPoint, new Vector3f(1, 1, 1), model.getFaces(), f);
        // 偶数次相交表示在外部
        return hitCount % 2 == 0;
    }


    private  int countRayIntersections(Vector3f origin, Vector3f direction, List<Face> faces, Face excludeFace) {
        int count = 0;
        for (Face face : faces) {
            if (face != excludeFace && rayIntersectsFace(origin, direction, face)) {
                count++;
            }
        }
        return count;
    }

    private boolean rayTriangleIntersect(Vector3f rayOrigin, Vector3f rayDirection,
                                         Vector3f v0, Vector3f v1, Vector3f v2) {
        Vector3f edge1 = new Vector3f(v1).sub(v0); // 三角形边v0->v1
        Vector3f edge2 = new Vector3f(v2).sub(v0); // 三角形边v0->v2

        // 计算行列式
        Vector3f h = new Vector3f(rayDirection).cross(edge2);
        float a = edge1.dot(h);
        // 射线与三角形平行时无交点
        if (a > -1e-6f && a < 1e-6f) return false;
        float f = 1.0f / a;
        Vector3f s = new Vector3f(rayOrigin).sub(v0);
        float u = f * s.dot(h);
        // u超出[0,1]范围时无交点
        if (u < 0.0f || u > 1.0f) return false;
        Vector3f q = new Vector3f(s).cross(edge1);
        float v = f * rayDirection.dot(q);
        // v超出[0,1]或u+v超过1时无交点
        if (v < 0.0f || u + v > 1.0f) return false;
        // 计算t值判断交点距离
        float t = f * edge2.dot(q);
        final float EPSILON = 1e-6f;
        if (t > -EPSILON && t < EPSILON) return false;

        return false;
    }
    private  boolean rayIntersectsFace(Vector3f origin, Vector3f direction, Face face) {
        Vector3f v0 = new Vector3f(model.getVertices().get(face.getVertexIndices()[0])) ;
        Vector3f v1 = new Vector3f(model.getVertices().get(face.getVertexIndices()[1])) ;
        Vector3f v2 = new Vector3f(model.getVertices().get(face.getVertexIndices()[2])) ;

        Vector3f edge1 = v1.sub(v0);
        Vector3f edge2 = v2.sub(v0);
        Vector3f h = direction.cross(edge2);
        double a = edge1.dot(h);

        if (Math.abs(a) < 1e-6) {
            return false; // 平行
        }

        double f = 1.0 / a;
        Vector3f s = origin.sub(v0);
        double u = f * s.dot(h);

        if (u < 0 || u > 1) {
            return false;
        }

        Vector3f q = s.cross(edge1);
        double v = f * direction.dot(q);

        if (v < 0 || u + v > 1) {
            return false;
        }

        double t = f * edge2.dot(q);
        return t > 1e-6; // 交点在前方
    }



}
